package incid

import (
	"errors"
	"hash/fnv"
	"log"
	"net"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/sony/sonyflake"
)

var (
	sf   *sonyflake.Sonyflake
	once sync.Once
)

func initSonyflake() {
	settings := sonyflake.Settings{
		StartTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
		MachineID: getMachineIDFromAllMACs,
	}
	sf = sonyflake.NewSonyflake(settings)
	if sf == nil {
		log.Fatal("Can not init Sonyflake")
	}
}

func getMachineIDFromAllMACs() (uint16, error) {
	interfaces, err := net.Interfaces()
	if err != nil {
		return 0, err
	}

	var macs []string
	for _, interf := range interfaces {
		if interf.Flags&net.FlagUp == 0 || len(interf.HardwareAddr) == 0 {
			continue
		}
		macs = append(macs, interf.HardwareAddr.String())
	}

	if len(macs) == 0 {
		return 0, errors.New("Do not find valid NIC mac address")
	}

	sort.Strings(macs)
	combinedMACs := strings.Join(macs, "")

	return hashStringToUint16(combinedMACs), nil
}

func hashStringToUint16(s string) uint16 {
	hasher := fnv.New32a()
	hasher.Write([]byte(s))
	hash32 := hasher.Sum32()
	return uint16(hash32 & 0xFFFF)
}

func GetId() int64 {
	return GetIdWithEntity(nil)
}

func GetIdWithEntity(entity interface{}) int64 {
	once.Do(initSonyflake)

	id, err := sf.NextID()
	if err != nil {
		log.Fatalf("Generate ID fail: %v", err)
	}
	return int64(id)
}
